package com.boot2.core.web.xss;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * 过滤尖括号等特殊字符串，解决xss问题
 * 
 * @author zhangweilin
 * @date 2017年4月1日 上午10:16:11
 * @version V1.0
 * @description
 */
//@Component
public class XssHttpServletFilter extends OncePerRequestFilter {
	protected Log loger = LogFactory.getLog(this.getClass());
	private String exclude = null; // 不需要过滤的路径集合
	private Pattern pattern = null; // 匹配不需要过滤路径的正则表达式

	public void setExclude(String exclude) {
		this.exclude = exclude;
		pattern = Pattern.compile(getRegStr(exclude));
	}

	/**
	 * 将传递进来的不需要过滤得路径集合的字符串格式化成一系列的正则规则
	 * 
	 * @param str
	 *            不需要过滤的路径集合
	 * @return 正则表达式规则
	 */
	private String getRegStr(String str) {
		if (StringUtils.isNotBlank(str)) {
			String[] excludes = str.split(";"); // 以分号进行分割
			int length = excludes.length;
			for (int i = 0; i < length; i++) {
				String tmpExclude = excludes[i];
				// 对点、反斜杠和星号进行转义
				tmpExclude = tmpExclude.trim();
				tmpExclude = tmpExclude.replace("\\", "\\\\").replace(".", "\\.").replace("*", ".*");

				tmpExclude = "^" + tmpExclude + "$";
				excludes[i] = tmpExclude;
			}
			return StringUtils.join(excludes, "|");
		}
		return str;
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
		String requestURI = request.getRequestURI();
		if (StringUtils.isNotBlank(requestURI)) {
			requestURI = requestURI.replace(request.getContextPath(), "");
		}
		if (null != pattern && pattern.matcher(requestURI).matches()) {
			chain.doFilter(request, response);
		} else {
			try {
				XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(request);
				chain.doFilter(xssRequest, response);
			} catch (Exception e) {
				e.printStackTrace();
				loger.error("Xss过滤器，包装request对象失败，" + e.getMessage(), e);
				chain.doFilter(request, response);
			}
		}
	}
}
